/**
 * 
 */
package com.amoby.main.service.impl;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.amoby.base.common.Constants;
import com.amoby.base.common.HttpUtils;
import com.amoby.base.utils.DateUtil;
import com.amoby.main.entity.AlipayOrder;
import com.amoby.main.entity.Business;
import com.amoby.main.mapper.AlipayMapper;
import com.amoby.main.mapper.AlipayOrderMapper;
import com.amoby.main.mapper.BusinessMapper;
import com.amoby.main.service.AlipayService;
import com.amoby.main.service.SmsService;

/**
 * @Copyright: 本内容仅限于重庆爱赢科技有限公司内部使用，禁止转发.
 * @Author: daijiangguo 2015年1月14日 下午5:17:00
 * @Version: $Id$
 * @Desc: <p>
 *        </p>
 */
@Service
public class AlipayServiceImpl implements AlipayService {
    private static Log            logger = LogFactory.getLog(AlipayServiceImpl.class);
    @Autowired
    private BusinessMapper        businessMapper;
    @Autowired
    private SmsService            smsService;
    @Autowired
    private AlipayOrderMapper     alipayOrderMapper;
    @Autowired
    private AlipayMapper   alipayMapper;
  
    public static String code = "GBK";

    /**
     * 生成要请求给支付宝的参数数组
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    @SuppressWarnings("unused")
    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
        // 除去数组中的空值和签名参数
        Map<String, String> sPara = paraFilter(sParaTemp);
        // 生成签名结果
        String mysign = buildRequestMysign(sPara);
        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", "MD5");
        return sPara;
    }

    /**
     * 生成要请求给支付宝的参数数组
     * @param sParaTemp 请求前的参数数组
     * @return 要请求的参数数组
     */
    private static Map<String, String> buildActivityRequestPara(Map<String, String> sParaTemp) {
        // 除去数组中的空值和签名参数
        Map<String, String> sPara = paraFilter(sParaTemp);
        // 生成签名结果
        String mysign = buildActivityRequestMysign(sPara);
        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", "MD5");
        return sPara;
    }

    /**
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /**
     * 生成签名结果
     * @param sPara 要签名的数组
     * @return 签名结果字符串
     */
    public static String buildRequestMysign(Map<String, String> sPara) {
        String prestr = createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        return DigestUtils.md5Hex(getContentBytes(prestr + Constants.ALIPAY_MD5_KEY, code));
    }

    /**
     * 生成签名结果 廖江红 添加，签名的key 不一样 支付宝服务窗支付的订单 进行退款签名 2015-11-20
     * @param sPara 要签名的数组
     * @return 签名结果字符串
     */
    public static String buildActivityRequestMysign(Map<String, String> sPara) {
        String prestr = createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        return DigestUtils.md5Hex(getContentBytes(prestr + Constants.ALIPAY_ACTIVITY_KEY, code));
    }

    
    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    /**
     * MD5 签名机制 廖江红 添加
     * @param text
     * @param key
     * @param input_charset
     * @return
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    @Override
    public Map<String, String> createAlipayCode(String merchantId, String merchantName) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("biz_type", "OVERSEASHOPQRCODE");
        JSONObject process = new JSONObject();
        process.put("secondary_merchant_industry", "5311");// 二级商户类型，百货行业
        process.put("secondary_merchant_id", merchantId);
        process.put("secondary_merchant_name", merchantName);
        process.put("trans_currency", Constants.ALIPAY_ACTIVITY_CURRENCY);
        process.put("currency", Constants.ALIPAY_ACTIVITY_CURRENCY);
        map.put("biz_data", process.toString());
        System.out.println(process.toString());
        map.put("notify_url", Constants.SYSTEM_URL + "/alipay.hdcall");
        map.put("sendFormat", "normal");
        map.put("_input_charset", "GBK");
        map.put("service", "alipay.commerce.qrcode.create");
        map.put("partner", Constants.ALIPAY_ACTIVITY_PID);
        map.put("timestamp", DateUtil.getDatetime());// 接口调用时间,此时间目前以北京时间为准，格式为：yyyy-MM-dd HH:mm:ss。
        map.put("biz_data", process.toString());
        //String sign = sign(createLinkString(paraFilter(map)), Constants.ALIPAY_MD5_KEY, "GBK");
        String error = "";
        logger.debug("生成二维码参数========="+map);
        try {
            Map<String, String> sPara = buildActivityRequestPara(map);// 请求参数
            // Map<String, String> sPara = buildActivityRequestPara(params);
            String url = "https://intlmapi.alipay.com/gateway.do";
            String rep = HttpUtils.getInstance().httpPost(url, sPara, code);
            logger.debug("生成二维码返回结果集================"+rep);
            Document doc = DocumentHelper.parseText(rep); // 将字符串转为XML
            String is_success = doc.selectSingleNode("//is_success").getText();// 判断二维码是否生成成功
            if ("T".equals(is_success)) {// 生成商户二维吗成功
                // 商户支付宝二维码
                map.clear();
                Map<String, Object> param = new HashMap<String, Object>();
                map.put("result", "success");
                map.put("message", "生成成功");
                String qrcode = doc.selectSingleNode("//qrcode").getText();
                param.put("qrcode", qrcode.substring(qrcode.lastIndexOf("com/") + 4));
                param.put("qrcode_img_url", doc.selectSingleNode("//qrcode_img_url").getText());
                param.put("id", merchantId);
                businessMapper.saveQrcode(param);
            } else {// 生成商户二维码失败
                map.clear();
                map.put("result", "fail");
                error = doc.selectSingleNode("//error").getText();
                map.put("message", error);
                map.put("qrcode_img_url", "");
            }
        } catch (Exception e) {
            map.clear();
            map.put("result", "fail");
            map.put("message", error);
            map.put("qrcode_img_url", "");
            logger.error("境外商户生成支付宝二维异常" + error, e);
        }
        return map;
    }


    
    public static void main1(String[] args) throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        params.put("_input_charset", "GBK");
        params.put("partner", "2088121965988715");
        params.put("service", "alipay.acquire.overseas.spot.refund");
        //params.put("alipay_trans_id", ao.getTradeNo());// 支付交易号
        params.put("partner_trans_id", "0120466572831455759291272");// 澳新通订单号
        params.put("partner_refund_id", "NG681455759301366423");// 商户退款交易号
        params.put("sendFormat", "normal");
        // 退款金额
        params.put("refund_amount", "0.01");
        params.put("currency", "AUD");
        params.put("refund_reson", "退款");
        logger.debug("退款参数======================="+params);
        Map<String, String> sPara = buildActivityRequestPara(params);
        
        logger.debug("退款参数加密后======================="+sPara);
        String url = "https://mapi.alipay.com/gateway.do";
        String rep = HttpUtils.getInstance().httpPost(url, sPara, code);
        System.err.println(rep);
    }
    
    @Override
    public Map<String, Object> alipayorderRefund(String orderNo) {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            AlipayOrder ao = alipayOrderMapper.selectAlipayOrderByNo(orderNo);
            if (ao == null) {
                map.put("r", "fail");
                map.put("m", "订单不存在");
                return map;
            }
            if (ao.getState() == 0) {
                map.put("r", "fail");
                map.put("m", "订单未支付成功");
                return map;
            }
            if (ao.getState() == 1) {// 调用退款接口
                Map<String, Object> alipayRecord = alipayMapper.getAlipayRecordByTradeNo(ao.getTradeNo());
                Map<String, String> params = new HashMap<String, String>();
                params.put("_input_charset", "GBK");
                params.put("partner", Constants.ALIPAY_ACTIVITY_PID);
                params.put("service", "alipay.acquire.overseas.spot.refund");
                //params.put("alipay_trans_id", ao.getTradeNo());// 支付交易号
                params.put("partner_trans_id", String.valueOf(alipayRecord.get("out_trade_no")));// 澳新通订单号
                params.put("partner_refund_id", ao.getTradeNo());// 商户退款交易号
                params.put("sendFormat", "normal");
                // 退款金额
                params.put("refund_amount", String.valueOf(ao.getAmount()));
                params.put("currency", currency);
                params.put("refund_reson", "退款");
                //params.put("notify_url", Constants.MANAGER_SYSTEM_DOMAIN + "/alipay.notify");
                logger.debug("退款参数======================="+params);
                Map<String, String> sPara = buildActivityRequestPara(params);
                logger.debug("退款参数加密后======================="+sPara);
                String url = "https://mapi.alipay.com/gateway.do";
                String rep = HttpUtils.getInstance().httpPost(url, sPara, code);
                Document doc = DocumentHelper.parseText(rep); // 将字符串转为XML
                String is_success = doc.selectSingleNode("//is_success").getText();// 判断是退款成功
                String result_code = doc.selectSingleNode("//result_code").getText();// 判断是退款成功
                logger.debug("支付宝正向扫码支付退款=" + rep + "==" + orderNo +"======"+result_code);
                if ("T".equals(is_success) && "SUCCESS".equals(result_code)) {// 判断是退款成功
                    ao.setRefundStatus((byte) 4);
                    ao.setUptime(DateUtil.getCurDate());
                    if (alipayOrderMapper.updateByPrimaryKeySelective(ao) > 0) {
                        map.put("r", "success");
                        map.put("m", "退款成功");
                        return map;
                    }
                } else {
                    map.put("r", "fail");
                    map.put("m", "退款失败" + doc.selectSingleNode("//error").getText());
                    return map;
                }
            } else {
                logger.debug("支付宝服务窗支付退款失败原因=" + orderNo);
                map.put("r", "fail");
                map.put("m", "退款失败");
                return map;
            }
        } catch (Exception e) {
            logger.error("支付宝服务窗支付退款异常=" + orderNo, e);
            map.put("r", "fail");
            map.put("m", "退款异常");
            return map;
        }
        return map;
    }
    /**申请退款 */
    @Override
    public Map<String, Object> alipayOrderSqRefund(String orderNo) {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            AlipayOrder ao = alipayOrderMapper.selectAlipayOrderByNo(orderNo);
            if (ao == null) {
                map.put("r", "fail");
                map.put("m", "订单不存在");
                return map;
            }
            if (ao.getState() == 0) {
                map.put("r", "fail");
                map.put("m", "订单未支付成功");
                return map;
            }
            if (ao.getState() == 1) {// 调用退款接口
                Map<String, Object> alipayRecord = alipayMapper.getAlipayRecordByTradeNo(ao.getTradeNo());
                Map<String, String> params = new HashMap<String, String>();
                params.put("_input_charset", "GBK");
                params.put("partner", Constants.ALIPAY_ACTIVITY_PID);
                params.put("service", "alipay.acquire.overseas.spot.refund");
                params.put("partner_trans_id", String.valueOf(alipayRecord.get("out_trade_no")));// 澳新通订单号
                params.put("partner_refund_id", ao.getTradeNo());// 商户退款交易号
                params.put("sendFormat", "normal");
                // 退款金额
                params.put("refund_amount", String.valueOf(ao.getAmount()));
                params.put("currency", currency);
                params.put("refund_reson", "申请退款");
                //params.put("notify_url", Constants.MANAGER_SYSTEM_DOMAIN + "/alipay.notify");
                logger.debug("退款参数======================="+params);
                Map<String, String> sPara = buildActivityRequestPara(params);
                logger.debug("退款参数加密后======================="+sPara);
                String url = "https://mapi.alipay.com/gateway.do";
                String rep = HttpUtils.getInstance().httpPost(url, sPara, code);
                Document doc = DocumentHelper.parseText(rep); // 将字符串转为XML
                String is_success = doc.selectSingleNode("//is_success").getText();// 判断是退款成功
                String result_code = doc.selectSingleNode("//result_code").getText();// 判断是退款成功
                logger.debug("支付宝正向扫码支付退款=" + rep + "==" + orderNo +"======"+result_code);
                if ("T".equals(is_success) && "SUCCESS".equals(result_code)) {// 判断是退款成功
                    String payTime = new SimpleDateFormat("yyyy-MM-dd").format(ao.getPayTime());
                    if(payTime.equals(DateUtil.getDate())){
                        ao.setRefundStatus((byte) 4);
                        ao.setUptime(DateUtil.getCurDate());
                        if (alipayOrderMapper.updateByPrimaryKeySelective(ao) > 0) {
                            map.put("r", "success");
                            map.put("m", "退款成功");
                            return map;
                        }
                    }else{
                        ao.setRefundStatus((byte) 4);
                        ao.setUptime(DateUtil.getCurDate());
                        if (alipayOrderMapper.updateByPrimaryKeySelective(ao) > 0) {
                            map.put("r", "success");
                            map.put("m", "退款成功，金额当日23点后到账");
                            return map;
                        }
                    }
                } else {
                    map.put("r", "fail");
                    map.put("m", "退款失败" + doc.selectSingleNode("//error").getText());
                    return map;
                }
            } else {
                logger.debug("支付宝服务窗支付退款失败原因=" + orderNo);
                map.put("r", "fail");
                map.put("m", "退款失败");
                return map;
            }
        } catch (Exception e) {
            logger.error("支付宝服务窗支付退款异常=" + orderNo, e);
            map.put("r", "fail");
            map.put("m", "退款异常");
            return map;
        }
        return map;
    }
    
    public static void main(String[] args) {
        String payTime = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        System.out.println(payTime.equals(DateUtil.getDate()));
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = java.lang.Exception.class)
    public boolean addAlipayOrder(Map<String, String> params) {
        logger.debug("支付宝服务窗扫码付款回调处理开始===========" + params);
        boolean falg = false;
        // 交易状态
        String trade_status = params.get("trade_status");
        if (trade_status.equals("TRADE_FINISHED")) {// 支付成功
            // 商户唯一订单号，
            String out_trade_no = params.get("out_trade_no");
            AlipayOrder ao = alipayOrderMapper.selectAlipayOrderByNo(out_trade_no);
            if (ao == null || (ao != null && ao.getState() == 1)) {
                falg = false;
            } else {
                // 支付宝交易号
                String trade_no = params.get("trade_no");
                ao.setTradeNo(trade_no);
                // 支付金额
                Double total_fee = Double.valueOf(params.get("total_fee"));
                // 支付宝回调时间
                // Date notify_time=DateUtil.paseDatetime(params.get("notify_time"));
                // ao.setUptime(notify_time);
                ao.setAmount(total_fee);
                ao.setPayTime(DateUtil.getCurDate());// 支付成功时间，取澳洲时间
                // 查询改订单 消费者信息
                Map<String, String> curMap = singleTradeQuery(params);
                if ("".equals(curMap.get("buyer")) || "".equals(curMap.get("buyerId"))) {
                    curMap = singleTradeQuery(params);
                    logger.debug("重复查询1=" + curMap.get("buyerId") + "===" + curMap.get("buyer"));
                }
                if ("".equals(curMap.get("buyer")) || "".equals(curMap.get("buyerId"))) {
                    curMap = singleTradeQuery(params);
                    logger.debug("重复查询2=" + curMap.get("buyerId") + "===" + curMap.get("buyer"));
                }
                if ("".equals(curMap.get("buyer")) || "".equals(curMap.get("buyerId"))) {
                    curMap = singleTradeQuery(params);
                    logger.debug("重复查询3=" + curMap.get("buyerId") + "===" + curMap.get("buyer"));
                }
                ao.setBuyer(curMap.get("buyer").toString());
                ao.setState((byte) 1);// 支付成功
                ao.setUptime(DateUtil.getCurDate());
                if (alipayOrderMapper.updateByPrimaryKeySelective(ao) > 0) {
                    // 查询出对应商家信息
                    falg = true;
                    Business business = businessMapper.selectByPrimaryKey(ao.getBsId());
                    if (business != null) {
                        /** 向商家发送短信 */
                        String code = ao.getOrderNo().substring(ao.getOrderNo().length() - 4);// 验证码
                        Double amount = ao.getAmount();// 消费金额
                        if (business.getPhone() != null && !"".equals(business.getPhone()) && !"".equals(business.getShopName())
                                && business.getShopName() != null) {
                            String content = "[" + code + "]" + " The payment amount of $" + amount
                                    + " has been processed successfully http://mmobile.e-swipe.com.au/ ." + Constants.SMS_LAST_STR;
                            smsService.sendBatchEventMessage(business.getPhone(), business.getPhone2(), business.getPhone3(), business.getPhone4(),
                                    business.getPhone5(), content);
                            logger.debug("短信发送内容=====================================" + content);
                        }
                        String buyerId = "".equals(curMap.get("buyerId").toString()) ? singleTradeQuery(params).get("buyerId") : curMap
                                .get("buyerId").toString();
                        // 向买家发送消息推送
                        /*if (!"".equals(buyerId)) {
                            AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient();
                            // 使用SDK，构建单发请求模型
                            AlipayMobilePublicMessageCustomSendRequest request = new AlipayMobilePublicMessageCustomSendRequest();
                            request.setBizContent(AlipayMsgBuildUtil.buildSingleImgTextMsg(buyerId, code, amount, ao.getToken()));
                            try {
                                // 使用SDK，调用单发接口发送图文消息
                                AlipayMobilePublicMessageCustomSendResponse response = alipayClient.execute(request);
                                // 这里只是简单的打印，请开发者根据实际情况自行进行处理
                                if (null != response && response.isSuccess()) {
                                    logger.debug("消息发送成功 : response = " + response.getBody());
                                } else {
                                    logger.debug("消息发送失败 code=" + response.getCode() + "msg=" + response.getMsg());
                                }
                            } catch (AlipayApiException e) {
                                logger.error("消息发送失败", e);
                            }
                        }*/
                    }
                    logger.debug("支付宝服务窗扫码付款回调处理结束===========" + ao.getOrderNo());
                }
            }
        }
        return falg;
    }

    @Override
    public Map<String, String> singleTradeQuery(Map<String, String> params) {
        Map<String, String> query = new HashMap<String, String>();
        // 查询买家信息
        query.put("_input_charset", "GBK");
        query.put("partner", Constants.ALIPAY_ACTIVITY_PID);
        query.put("service", "single_trade_query");
        query.put("trade_no", params.get("trade_no").toString());// 支付交易号
        query.put("out_trade_no", params.get("out_trade_no").toString());// 澳新通订单号
        Map<String, String> sPara = buildActivityRequestPara(query);
        String url = "https://www.alipay.com/cooperate/gateway.do";
        try {
            String rep = HttpUtils.getInstance().httpPost(url, sPara, code);
            logger.debug("查询购买用户信息接口=订单号=" + params.get("trade_no").toString() + "==返回结果==" + rep);
            Document doc = DocumentHelper.parseText(rep); // 将字符串转为XML
            String is_success = doc.selectSingleNode("//is_success").getText();
            if ("T".equals(is_success)) {// 生成商户二维吗成功
                String buyer = doc.selectSingleNode("//buyer_email").getText();
                String buyerId = doc.selectSingleNode("//buyer_id").getText();
                params.put("buyer", buyer);
                params.put("buyerId", buyerId);
            } else {
                params.put("buyer", "");
                params.put("buyerId", "");
            }
        } catch (Exception e) {
            params.put("buyer", "");
            params.put("buyerId", "");
            logger.error("查询支付宝单笔订单买家的信息异常=" + params.get("out_trade_no").toString() + "查询时间=" + DateUtil.getDatetime(), e);
        }
        return params;
    }
}
